/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.mvc.wrapper;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.zhg2yqq.wheels.mvc.annotation.FieldEncrypt;
import com.zhg2yqq.wheels.mvc.util.FieldEncryptUtil;

import cn.hutool.core.text.CharSequenceUtil;

/**
 * @author zhg2yqq, 2022年12月6日
 * @version zhg2yqq v1.0
 */
public class EncryptQueryWrapper<T> extends QueryWrapper<T> implements BaseWapper<T> {
    private static final long serialVersionUID = 1L;
    private String encryptKey;
    private Class<T> genericType;
    private Map<String, Field> entityEncryptFields = new HashMap<>();

    public EncryptQueryWrapper() {
        super();
    }

    @SuppressWarnings("unchecked")
    public EncryptQueryWrapper(T entity) {
        super(entity);
        if (entity != null) {
            genericType = (Class<T>) entity.getClass();
            initEntityEncryptFields();
        }
    }

    @SuppressWarnings("unchecked")
    public EncryptQueryWrapper(T entity, String... columns) {
        super(entity, columns);
        if (entity != null) {
            genericType = (Class<T>) entity.getClass();
            initEntityEncryptFields();
        }
    }

    public EncryptQueryWrapper(String key, T entity) {
        this(entity);
        this.encryptKey = key;
    }

    public EncryptQueryWrapper(String key, T entity, String... columns) {
        this(entity, columns);
        this.encryptKey = key;
    }

    public EncryptQueryWrapper(String key, Class<T> genericType) {
        super();
        this.encryptKey = key;
        this.genericType = genericType;
        initEntityEncryptFields();
    }

    private void initEntityEncryptFields() {
        Field[] fields = getGenericTypeAllEncryptFields();
        if (fields != null) {
            for (Field f : fields) {
                entityEncryptFields.put(f.getName(), f);
            }
        }
    }

    protected Object getEncryptVal(boolean condition, String column, Object val) {
        if (condition) {
            Field encryptField = entityEncryptFields.get(column);
            if (encryptField != null) {
                FieldEncrypt annotation = encryptField.getAnnotation(FieldEncrypt.class);
                String key = CharSequenceUtil.isEmpty(annotation.encryptorPassword()) ? encryptKey
                        : annotation.encryptorPassword();
                return FieldEncryptUtil.encrypt(key, val);
            }
        }
        return val;
    }

    protected Collection<?> getEncryptValColl(boolean condition, String column,
                                              Collection<?> coll) {
        if (condition) {
            Field encryptField = entityEncryptFields.get(column);
            if (encryptField != null && coll != null) {
                FieldEncrypt annotation = encryptField.getAnnotation(FieldEncrypt.class);
                String key = CharSequenceUtil.isEmpty(annotation.encryptorPassword()) ? encryptKey
                        : annotation.encryptorPassword();
                return coll.stream().map(val -> FieldEncryptUtil.encrypt(key, val))
                        .collect(Collectors.toList());
            }
        }
        return coll;
    }

    @Override
    protected QueryWrapper<T> addCondition(boolean condition, String column, SqlKeyword sqlKeyword,
                                           Object val) {
        Object value = getEncryptVal(condition, column, val);
        return super.addCondition(condition, column, sqlKeyword, value);
    }

    @Override
    public QueryWrapper<T> in(boolean condition, String column, Collection<?> coll) {
        Collection<?> value = getEncryptValColl(condition, column, coll);
        return super.in(condition, column, value);
    }

    @Override
    public QueryWrapper<T> in(boolean condition, String column, Object... values) {
        if (values == null) {
            return super.in(condition, column, values);
        }
        Collection<?> value = getEncryptValColl(condition, column, Arrays.asList(values));
        return super.in(condition, column, value.toArray());
    }

    @Override
    public QueryWrapper<T> notIn(boolean condition, String column, Collection<?> coll) {
        Collection<?> value = getEncryptValColl(condition, column, coll);
        return super.notIn(condition, column, value);
    }

    @Override
    public QueryWrapper<T> notIn(boolean condition, String column, Object... values) {
        if (values == null) {
            return super.notIn(condition, column, values);
        }
        Collection<?> value = getEncryptValColl(condition, column, Arrays.asList(values));
        return super.notIn(condition, column, value);
    }

    @Override
    public Class<T> getGenericType() {
        return genericType;
    }
}
